/**
 * Copyright (c) 2012, Brent Mucci
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/

#include "mcl_bitstream_reader.hpp"

using namespace mcl;

BitstreamReader::BitstreamReader(std::vector<char> &vec) : m_vec(vec)
{
	m_bitPos = 0;
	m_bytePos = 0;
}

BitstreamReader::~BitstreamReader()
{

}

// *** See ITU-T June 2011 specification on the following methods:
bool BitstreamReader::byte_aligned()
{
	// It is byte aligned if the bit position offset (from within a byte) is 0.
	return !m_bitPos;
}

bool BitstreamReader::more_data_in_byte_stream()
{
	// If the primary buffer is of size zero then the stream is exhausted, otherwise true.
	return m_bytePos < m_vec.size();
}

bool BitstreamReader::more_rbsp_data()
{
	// If there is no more data to be read in to a RBSP, return false.
	if(!more_data_in_byte_stream())
	{
		return false;
	}
	else if(byte_aligned())
	{
		// The byte is aligned, therefore the stop bit should be 1 (msb) followed by seven 0 (lsb); return true. 
		// Return false otherise (b/c something is wrong with the bitstream).
		return peek(8) == 128;
	}

	// Byte is not aligned, scan through from right (lsb) to left (msb) until the first 1 is spotted.
	// Condition 1: If the first 1 is spotted before the last bit position in the loop (right to left scan), 
	//              return true (data exists before the stop bit).
	// Condition 2: Return false if the 1 is spotted ONLY in the msb position at the very end of the loop 
	//              (nothing is wrong, there is just nothing left to read before the stop bit).
	// Condition 3: If no 1 is spotted before the loop finishes then return false (something is wrong with the bitstream).
	unsigned int numBitsAlign = bitsToAlign();
	unsigned int bits = peek(numBitsAlign); // Up to 7 bits will be read, fewer may be returned; minimum is 1.
	unsigned int mask = 1;

	// Scan for more at least a 1, starting from the RHS (LSB). Note: This will skip if the numBitsAlign is 0 (aligned).
	for(unsigned int i = 1; i <= numBitsAlign; i++)
	{
		if(bits & mask)
		{
			// Found a 1 in the bitstream
			if(i == numBitsAlign)
			{
				// The 1 was found in the msb position, condition 2 applies.
				return false;
			}
			// The 1 was found before the msb position, condition 1 applies.
			return true;
		}
		bits = bits >> 1;
	}
	
	// Return false otherwise, most likely something is wrong with the bitstream. Condition 3 is the most likely candidate.
	return false;
}

bool BitstreamReader::more_rbsp_trailing_data()
{
	return more_data_in_byte_stream();
}

void BitstreamReader::rbsp_trailing_bits()
{
	/* rbsp_stop_one_bit = */ read_bits(1);
	while(!byte_aligned())
		/* rbsp_alignment_zero_bit = */ read_bits(1);
}

unsigned int BitstreamReader::next_bits(unsigned int n)
{
	return peek(n);
}

unsigned int BitstreamReader::read_bits(unsigned int n)
{
	unsigned int bits = peek(n);
	step(n);
	return bits;
}

// Once data has been read in, step the bitstream bit position forward.
void BitstreamReader::step(unsigned int bits)
{
	// Increase the bit position within the buffer by a_bits.
	m_bitPos += bits;
	// After 8 bits or more have been read in, increment the byte position by the number of whole bytes that have been read.
	m_bytePos += m_bitPos >> 3;
	// Equivalent to m_bufferBitPos %= 8, only the byte remainder is of interest.
	m_bitPos &= 7;
}

// Return an integer containing a number of bits that have been peeked.
unsigned int BitstreamReader::peek(unsigned int bits)
{
	unsigned int readBits = 0;

	// ((a_bits & 7) ? 1 : 0) = rounding up to an extra byte. numBytes is the ceiling limit of the number of bytes to be read in.
	unsigned int numBytes = (bits >> 3) + ((bits & 7) ? 1 : 0);

	// CAUTION: The buffer is assumed to be much less than 4 GB, specifically 4 GB - m_primaryBufferSize.
	if(m_bytePos + (bits >> 3) > m_vec.size())
	{
		return 0;
	}
	else if(bits > 0)
	{
		// All of The bits being read are from the primary buffer.
		readBits = m_vec[m_bytePos];
		for(unsigned int i = 1; i < numBytes; i++)
		{
			readBits = readBits << 8;
			readBits |= m_vec[m_bytePos + i];
		}
	}
	// To be shifted to the right by the number of bits, within a byte, that have not been read in 
	// (complement of the number of bits within a byte that have been read in).
	readBits = readBits >> (((numBytes << 3) - (bits & 7)) & 7);
	return readBits;
}

// The number of bits necessary to reach the next byte alignment.
unsigned int BitstreamReader::bitsToAlign()
{
	if(byte_aligned()) return 0;
	return (m_bitPos ^ 7) + 1;
}

unsigned int BitstreamReader::read_bits_ue()
{
	unsigned int expGolombSuffix = 1;
	unsigned char leadingZeroBits,
		numZeros;
	// The maximum number of leading 0 bits, that include the terminating 1, is 32.
	for(numZeros = 0; numZeros < sizeof(unsigned int) << 3; numZeros++)
	{
		leadingZeroBits = read_bits(1);
		if(leadingZeroBits)
		{
			break;
		}
	}
	// If there are no leading 0s then return 0 (should actually throw an exception)
	if(!numZeros) return 0;
	// expGolombSuffix contains a 1 which will be a leading 1 once shifted, this is to form a binary pattern found in unsigned exp golomb decoding.
	expGolombSuffix = expGolombSuffix << numZeros;
	expGolombSuffix |= read_bits(numZeros);

	// Decode the suffix, do this by subtracting 1 from the terminating 1 followed by the suffix (this is a decode pattern).
	return expGolombSuffix - 1;
}

// Code cloning is acceptable to prevent additional stacking.
signed int BitstreamReader::read_bits_se()
{
	unsigned int expGolombSuffix = 1, codeNum, elementReturnValue;
	unsigned char leadingZeroBits,
		numZeros;
	// The maximum number of leading 0 bits, that include the terminating 1, is 32.
	for(numZeros = 0; numZeros < sizeof(unsigned int) << 3; numZeros++)
	{
		leadingZeroBits = read_bits(1);
		if(leadingZeroBits)
		{
			break;
		}
	}
	// If there are no leading 0s then return 0 (should actually throw an exception)
	if(!numZeros) return 0;
	// expGolombSuffix contains a 1 which will be a leading 1 once shifted, this is to form a binary pattern found in unsigned exp golomb decoding.
	expGolombSuffix = expGolombSuffix << numZeros;
	expGolombSuffix |= read_bits(numZeros);
	// Decode the suffix, do this by subtracting 1 from the terminating 1 followed by the suffix (this is a decode pattern).
	codeNum = expGolombSuffix - 1;
	// Convert the code num into its partial return value [(codeNum / 2) = codeNum >> 1]
	elementReturnValue = (codeNum >> 1);
	// Apply a ceiling procedure, if necessary
	elementReturnValue += (codeNum & 1);
	// Apply the sign of the number, if applicable: (-1)*exp(codeNum + 1) = (codeNum ^ 1) << ((sizeof(unsigned int) << 3) - 1)
	return elementReturnValue | ((codeNum ^ 1) << ((sizeof(unsigned int) << 3) - 1));
}